package laf.learning;


import java.util.HashSet;
import java.util.Set;

import jade.content.ContentElement;
import jade.content.lang.Codec.CodecException;
import jade.content.onto.BeanOntologyException;
import jade.content.onto.OntologyException;
import jade.content.onto.UngroundedException;
import jade.core.behaviours.CyclicBehaviour;
import jade.domain.FIPANames;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import laf.agents.CognitiveAgent;
import laf.agents.LanguageSymbolDictionary;
import laf.agents.ObservationBase;
import laf.behaviours.BroadcastObservationBehaviour;
import laf.behaviours.ObservationBehaviour;
import laf.env.EnvObject;
import laf.env.ObjectIdentifier;
import laf.env.Observation;
import laf.env.State;
import laf.lang.Describes;
import laf.onto.LAFOntology;

public class ReactiveSymbolGroundingBehaviour extends CyclicBehaviour {

	private static final long serialVersionUID = -4587901736627060244L;
	private MessageTemplate mt;
	protected CognitiveAgent myCognitiveAgent;
	private GroundingStrategy groundingStrategy;
	private boolean changed = false;
	
	public ReactiveSymbolGroundingBehaviour() {
		super();
	}

	public ReactiveSymbolGroundingBehaviour(CognitiveAgent a, GroundingStrategy groundingStrategy) {
		super(a);
		myCognitiveAgent = a;
		this.groundingStrategy = groundingStrategy;
	}

	@Override
	public void onStart() {
		mt = MessageTemplate.MatchPerformative(ACLMessage.INFORM);
		mt = MessageTemplate.and(mt, MessageTemplate.MatchLanguage(FIPANames.ContentLanguage.FIPA_SL));
		try {
			mt = MessageTemplate.and(mt, MessageTemplate.MatchOntology(LAFOntology.getInstance().getName()));
		} catch (BeanOntologyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// TODO msg filtering
		//mt = MessageTemplate.and(mt, MessageTemplate.not(MessageTemplate.MatchProtocol(FIPANames.InteractionProtocol.FIPA_QUERY)));
	}

	@Override
	public void action() {
		ACLMessage msg = myAgent.receive(mt);
		if (msg != null) {
			myCognitiveAgent.getLogger().info("Description recieved");
			try {
				ContentElement content = myAgent.getContentManager().extractContent(msg);
				final Describes describes;
				if (content instanceof Describes) {
					describes = (Describes) content;	
				} else {
					myCognitiveAgent.getLogger().severe("Content of message not understood. Describes predicate expected.");
					return;
				}
				ObjectIdentifier objectId = describes.getObjectIdentifier();				
				final ObservationBase observationBase = myCognitiveAgent.getObservationBase();
				
				// if there is no observation about object or observation is outdated
				if (!observationBase.contains(describes.getTime(), objectId)) {
					myAgent.addBehaviour(new ObservationBehaviour(myAgent, objectId) {

						@Override
						protected void handleResult(Observation observation) {
							observationBase.add(observation);
							myCognitiveAgent.getLogger().info("New observation: " + observation.toString());
							analize(describes, observation);
						}
					});
				} else {
					Observation observation = observationBase.get(describes.getTime(), objectId);
					analize(describes, observation);
				}
				
			} catch (UngroundedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (CodecException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (OntologyException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			block();
		}		
	}

	protected void analize(Describes describes, Observation observation) {
		final LanguageSymbolDictionary dictionary = myCognitiveAgent.getDictionary();
		if (!changed  && dictionary.getMaxCredibility() > 300L) {
			groundingStrategy = new InvertedGroundingStrategy(groundingStrategy.getGroundingRule());
			changed = true;
			myCognitiveAgent.getLogger().info(myAgent.getLocalName() + ": Grounding strategy changed to inverted.");
		}
		if (describes.getTime() == observation.getTime()) {
			groundingStrategy.updateCorrelation(dictionary, describes.getSymbol(), observation.getValues());
		} else {
			myCognitiveAgent.getLogger().info(myAgent.getLocalName() + ": Object has already changed.");
		}
	}
}